<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SSE客户端测试</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            border-radius: 15px;
            box-shadow: 0 20px 40px rgba(0,0,0,0.1);
            overflow: hidden;
        }

        .header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 30px;
            text-align: center;
        }

        .header h1 {
            font-size: 2.5em;
            margin-bottom: 10px;
        }

        .header p {
            font-size: 1.1em;
            opacity: 0.9;
        }

        .content {
            padding: 30px;
        }

        .section {
            margin-bottom: 30px;
            padding: 20px;
            border: 1px solid #e0e0e0;
            border-radius: 10px;
            background: #fafafa;
        }

        .section h2 {
            color: #333;
            margin-bottom: 15px;
            font-size: 1.5em;
        }

        .form-group {
            margin-bottom: 15px;
        }

        .form-group label {
            display: block;
            margin-bottom: 5px;
            font-weight: 600;
            color: #555;
        }

        .form-group input, .form-group textarea {
            width: 100%;
            padding: 12px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 14px;
            transition: border-color 0.3s;
        }

        .form-group input:focus, .form-group textarea:focus {
            outline: none;
            border-color: #667eea;
        }

        .btn {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            padding: 12px 25px;
            border-radius: 8px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 600;
            transition: transform 0.2s, box-shadow 0.2s;
            margin-right: 10px;
            margin-bottom: 10px;
        }

        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
        }

        .btn:disabled {
            opacity: 0.6;
            cursor: not-allowed;
            transform: none;
        }

        .btn-danger {
            background: linear-gradient(135deg, #ff6b6b 0%, #ee5a52 100%);
        }

        .btn-success {
            background: linear-gradient(135deg, #51cf66 0%, #40c057 100%);
        }

        .btn-warning {
            background: linear-gradient(135deg, #ffd43b 0%, #fcc419 100%);
            color: #333;
        }

        .status {
            padding: 15px;
            border-radius: 8px;
            margin-bottom: 15px;
            font-weight: 600;
        }

        .status.connected {
            background: #d4edda;
            color: #155724;
            border: 1px solid #c3e6cb;
        }

        .status.disconnected {
            background: #f8d7da;
            color: #721c24;
            border: 1px solid #f5c6cb;
        }

        .status.connecting {
            background: #fff3cd;
            color: #856404;
            border: 1px solid #ffeaa7;
        }

        .messages {
            max-height: 400px;
            overflow-y: auto;
            border: 1px solid #ddd;
            border-radius: 8px;
            padding: 15px;
            background: white;
        }

        .message {
            padding: 10px;
            margin-bottom: 10px;
            border-radius: 6px;
            border-left: 4px solid #667eea;
            background: #f8f9fa;
        }

        .message.error {
            border-left-color: #dc3545;
            background: #f8d7da;
        }

        .message.success {
            border-left-color: #28a745;
            background: #d4edda;
        }

        .message.warning {
            border-left-color: #ffc107;
            background: #fff3cd;
        }

        .message .timestamp {
            font-size: 12px;
            color: #666;
            margin-bottom: 5px;
        }

        .message .event-type {
            font-weight: 600;
            color: #333;
            margin-bottom: 5px;
        }

        .message .data {
            font-family: 'Courier New', monospace;
            font-size: 13px;
            background: #f1f3f4;
            padding: 8px;
            border-radius: 4px;
            white-space: pre-wrap;
            word-break: break-all;
        }

        .stats {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin-bottom: 20px;
        }

        .stat-card {
            background: white;
            padding: 15px;
            border-radius: 8px;
            border: 1px solid #e0e0e0;
            text-align: center;
        }

        .stat-card .value {
            font-size: 2em;
            font-weight: bold;
            color: #667eea;
        }

        .stat-card .label {
            color: #666;
            font-size: 14px;
            margin-top: 5px;
        }

        .controls {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            margin-bottom: 20px;
        }

        .log {
            background: #2d3748;
            color: #e2e8f0;
            padding: 15px;
            border-radius: 8px;
            font-family: 'Courier New', monospace;
            font-size: 12px;
            max-height: 200px;
            overflow-y: auto;
            white-space: pre-wrap;
        }

        @media (max-width: 768px) {
            .container {
                margin: 10px;
                border-radius: 10px;
            }
            
            .header {
                padding: 20px;
            }
            
            .header h1 {
                font-size: 2em;
            }
            
            .content {
                padding: 20px;
            }
            
            .stats {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🔗 会话连接测试</h1>
            <p>测试与Java服务端的会话管理和流式通信</p>
        </div>

        <div class="content">
            <!-- 连接状态 -->
            <div class="section">
                <h2>📊 连接状态</h2>
                <div id="status" class="status disconnected">
                    未连接
                </div>
                <div class="stats">
                    <div class="stat-card">
                        <div id="sessionId" class="value">-</div>
                        <div class="label">会话ID</div>
                    </div>
                    <div class="stat-card">
                        <div id="userId" class="value">-</div>
                        <div class="label">用户ID</div>
                    </div>
                    <div class="stat-card">
                        <div id="reconnectAttempts" class="value">0</div>
                        <div class="label">重连次数</div>
                    </div>
                    <div class="stat-card">
                        <div id="messageCount" class="value">0</div>
                        <div class="label">消息数量</div>
                    </div>
                </div>
            </div>

            <!-- 连接控制 -->
            <div class="section">
                <h2>🔌 连接控制</h2>
                <div class="form-group">
                    <label for="baseUrl">服务端地址:</label>
                    <input type="text" id="baseUrl" value="http://localhost:8080" placeholder="请输入服务端地址">
                </div>
                <div class="form-group">
                    <label for="token">认证Token:</label>
                    <input type="text" id="token" placeholder="请输入用户认证Token">
                </div>
                <div class="form-group">
                    <label for="userId">用户ID:</label>
                    <input type="number" id="userId" placeholder="请输入用户ID">
                </div>
                <div class="controls">
                    <button id="connectBtn" class="btn btn-success">连接</button>
                    <button id="disconnectBtn" class="btn btn-danger" disabled>断开</button>
                    <button id="heartbeatBtn" class="btn btn-warning" disabled>发送心跳</button>
                    <button id="clearBtn" class="btn">清空消息</button>
                </div>
            </div>

            <!-- 消息发送 -->
            <div class="section">
                <h2>📤 消息发送</h2>
                <div class="form-group">
                    <label for="eventName">事件名称:</label>
                    <input type="text" id="eventName" value="notification" placeholder="请输入事件名称">
                </div>
                <div class="form-group">
                    <label for="messageData">消息数据 (JSON):</label>
                    <textarea id="messageData" rows="4" placeholder='{"title": "测试消息", "content": "这是一条测试消息"}'></textarea>
                </div>
                <div class="controls">
                    <button id="sendMessageBtn" class="btn" disabled>发送消息</button>
                    <button id="sendToUserBtn" class="btn" disabled>发送给用户</button>
                    <button id="broadcastBtn" class="btn" disabled>广播消息</button>
                </div>
            </div>

            <!-- 流式输出测试 -->
            <div class="section">
                <h2>🌊 流式输出测试</h2>
                <div class="form-group">
                    <label for="testMessage">测试消息:</label>
                    <input type="text" id="testMessage" placeholder="请输入要发送的消息">
                </div>
                <div class="form-group">
                    <label for="testSessionId">会话ID (可选):</label>
                    <input type="text" id="testSessionId" placeholder="SSE会话ID">
                </div>
                <div class="controls">
                    <button id="testStreamBtn" class="btn">测试流式输出</button>
                    <button id="clearStreamBtn" class="btn">清空流式输出</button>
                </div>
                <div class="form-group">
                    <label>流式输出结果:</label>
                    <div id="streamOutput" style="background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 4px; padding: 10px; height: 200px; overflow-y: auto; font-family: monospace; font-size: 12px;"></div>
                </div>
            </div>

            <!-- 用户位置分析 -->
            <div class="section">
                <h2>📍 用户位置分析</h2>
                <div class="form-group">
                    <label for="userLocationMessage">用户信息描述 (支持Markdown格式):</label>
                    <textarea id="userLocationMessage" rows="8" placeholder="请详细描述用户信息，包括行业、目标客户群体、营销需求等。支持Markdown格式。

例如：
# 用户信息分析

## 基本信息
- 行业：教育培训
- 细分领域：K12在线教育
- 主要业务区域：一线城市

## 目标客户
- 年龄：30-45岁家长群体
- 收入水平：中等收入
- 主要关注：孩子学习成绩提升

## 营销需求
- 推广渠道：社交媒体、搜索引擎
- 内容重点：教育理念、学习方法
- 品牌定位：专业、可信赖的教育伙伴"></textarea>
                </div>
                <div class="controls">
                    <button id="userLocationBtn" class="btn">分析用户位置</button>
                    <button id="clearUserLocationBtn" class="btn">清空分析结果</button>
                </div>
                <div class="form-group">
                    <label>分析结果:</label>
                    <div id="userLocationOutput" style="background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 4px; padding: 15px; height: 300px; overflow-y: auto; font-family: monospace; font-size: 12px; white-space: pre-wrap;"></div>
                </div>
            </div>

            <!-- 消息显示 -->
            <div class="section">
                <h2>📨 消息记录</h2>
                <div id="messages" class="messages">
                    <div class="message">
                        <div class="timestamp">等待连接...</div>
                        <div class="event-type">系统</div>
                        <div class="data">请先建立SSE连接</div>
                    </div>
                </div>
            </div>

            <!-- 控制台日志 -->
            <div class="section">
                <h2>📝 控制台日志</h2>
                <div id="log" class="log"></div>
            </div>
        </div>
    </div>

    <script src="sse-client.js"></script>
    <script>
        // 全局变量
        let sseClient = null;
        let messageCount = 0;
        let heartbeatInterval = null;

        // DOM元素
        const statusEl = document.getElementById('status');
        const sessionIdEl = document.getElementById('sessionId');
        const userIdEl = document.getElementById('userId');
        const reconnectAttemptsEl = document.getElementById('reconnectAttempts');
        const messageCountEl = document.getElementById('messageCount');
        const baseUrlEl = document.getElementById('baseUrl');
        const tokenEl = document.getElementById('token');
        const userIdInputEl = document.getElementById('userId');
        const eventNameEl = document.getElementById('eventName');
        const messageDataEl = document.getElementById('messageData');
        const messagesEl = document.getElementById('messages');
        const logEl = document.getElementById('log');
        
        // 流式输出相关元素
        const testMessageEl = document.getElementById('testMessage');
        const testSessionIdEl = document.getElementById('testSessionId');
        const streamOutputEl = document.getElementById('streamOutput');

        // 按钮元素
        const connectBtn = document.getElementById('connectBtn');
        const disconnectBtn = document.getElementById('disconnectBtn');
        const heartbeatBtn = document.getElementById('heartbeatBtn');
        const clearBtn = document.getElementById('clearBtn');
        const sendMessageBtn = document.getElementById('sendMessageBtn');
        const sendToUserBtn = document.getElementById('sendToUserBtn');
        const broadcastBtn = document.getElementById('broadcastBtn');
        const testStreamBtn = document.getElementById('testStreamBtn');
        const clearStreamBtn = document.getElementById('clearStreamBtn');

        // 初始化
        function init() {
            // 绑定事件
            connectBtn.addEventListener('click', connect);
            disconnectBtn.addEventListener('click', disconnect);
            heartbeatBtn.addEventListener('click', sendHeartbeat);
            clearBtn.addEventListener('click', clearMessages);
            sendMessageBtn.addEventListener('click', sendMessage);
            sendToUserBtn.addEventListener('click', sendToUser);
            broadcastBtn.addEventListener('click', broadcastMessage);
            testStreamBtn.addEventListener('click', testStream);
            clearStreamBtn.addEventListener('click', clearStreamOutput);
            userLocationBtn.addEventListener('click', analyzeUserLocation);
            clearUserLocationBtn.addEventListener('click', clearUserLocationOutput);

            // 设置默认值
            tokenEl.value = 'test-token-123';
            userIdInputEl.value = '1'; // 这个值会被用于获取sessionId
            messageDataEl.value = JSON.stringify({
                title: '测试消息',
                content: '这是一条来自前端的测试消息',
                timestamp: new Date().toISOString()
            }, null, 2);
            testMessageEl.value = '你好，请介绍一下你自己';

            log('会话连接测试页面已初始化');
        }

        // 连接SSE
        async function connect() {
            const baseUrl = baseUrlEl.value.trim();
            const token = tokenEl.value.trim();
            const userId = parseInt(userIdInputEl.value);

            if (!baseUrl || !token || !userId) {
                alert('请填写完整的连接信息');
                return;
            }

            try {
                updateStatus('connecting', '正在连接...');
                updateButtons(true, false);

                // 通过HTTP GET请求获取sessionId
                log('正在获取sessionId...');
                const sessionResponse = await fetch(`${baseUrl}/api/client/sse/connect?token=${encodeURIComponent(token)}&userId=${userId}`, {
                    method: 'GET',
                    headers: {
                        'token': token
                    }
                });

                if (!sessionResponse.ok) {
                    throw new Error(`获取sessionId失败: HTTP ${sessionResponse.status}`);
                }

                const sessionResult = await sessionResponse.json();
                if (sessionResult.code !== 200) {
                    throw new Error(`获取sessionId失败: ${sessionResult.message}`);
                }

                const sessionId = sessionResult.data.sessionId;
                log(`获取sessionId成功: ${sessionId}`);

                // 创建SSE客户端并设置sessionId
                sseClient = new SseClient(baseUrl);
                sseClient.sessionId = sessionId;
                sseClient.userId = userId;
                sseClient.token = token;
                sseClient.isConnected = true;
                
                // 设置事件监听器
                sseClient.on('connected', handleConnected);
                sseClient.on('disconnected', handleDisconnected);
                sseClient.on('error', handleError);
                sseClient.on('message', handleMessage);
                sseClient.on('reconnected', handleReconnected);
                sseClient.on('reconnect_failed', handleReconnectFailed);

                // 触发连接成功事件
                handleConnected({
                    sessionId: sessionId,
                    userId: userId,
                    timestamp: new Date().toISOString()
                });
                
                log(`连接成功，用户ID: ${userId}, sessionId: ${sessionId}`);
                
            } catch (error) {
                log(`连接失败: ${error.message}`);
                updateStatus('disconnected', '连接失败');
                updateButtons(false, false);
            }
        }

        // 断开连接
        async function disconnect() {
            if (sseClient) {
                try {
                    // 发送断开连接请求到服务器
                    const response = await fetch(`${baseUrlEl.value}/api/client/sse/close/${sseClient.userId}/${sseClient.sessionId}`, {
                        method: 'DELETE',
                        headers: {
                            'token': sseClient.token
                        }
                    });
                    
                    if (response.ok) {
                        log('连接已断开');
                    } else {
                        log('断开连接请求失败，但本地状态已更新');
                    }
                } catch (error) {
                    log(`断开连接失败: ${error.message}`);
                }
                
                // 清理本地状态
                sseClient.disconnect();
            }
            
            updateStatus('disconnected', '已断开连接');
            updateButtons(false, false);
            clearHeartbeat();
        }

        // 发送心跳
        async function sendHeartbeat() {
            if (!sseClient || !sseClient.sessionId) return;

            try {
                const response = await fetch(`${baseUrlEl.value}/api/client/sse/heartbeat/${sseClient.sessionId}`, {
                    method: 'GET',
                    headers: {
                        'token': sseClient.token
                    }
                });

                if (response.ok) {
                    const result = await response.json();
                    log('心跳发送成功');
                } else {
                    throw new Error(`心跳失败: ${response.status}`);
                }
            } catch (error) {
                log(`心跳发送失败: ${error.message}`);
            }
        }

        // 发送消息
        async function sendMessage() {
            const eventName = eventNameEl.value.trim();
            const data = messageDataEl.value.trim();

            if (!eventName || !data) {
                alert('请填写事件名称和消息数据');
                return;
            }

            try {
                let messageData;
                try {
                    messageData = JSON.parse(data);
                } catch (e) {
                    messageData = data;
                }

                const response = await fetch(`${baseUrlEl.value}/api/client/sse/send/${userIdInputEl.value}?eventName=${eventName}`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'token': tokenEl.value
                    },
                    body: JSON.stringify(messageData)
                });

                if (response.ok) {
                    const result = await response.json();
                    log(`消息发送成功: ${JSON.stringify(result)}`);
                    addMessage('success', '消息发送', `事件: ${eventName}\n数据: ${JSON.stringify(messageData, null, 2)}`);
                } else {
                    throw new Error(`HTTP ${response.status}`);
                }
            } catch (error) {
                log(`消息发送失败: ${error.message}`);
                addMessage('error', '消息发送失败', error.message);
            }
        }

        // 发送给用户
        async function sendToUser() {
            const eventName = eventNameEl.value.trim();
            const data = messageDataEl.value.trim();
            const targetUserId = prompt('请输入目标用户ID:');

            if (!eventName || !data || !targetUserId) {
                alert('请填写完整信息');
                return;
            }

            try {
                let messageData;
                try {
                    messageData = JSON.parse(data);
                } catch (e) {
                    messageData = data;
                }

                const response = await fetch(`${baseUrlEl.value}/api/client/sse/send/${targetUserId}?eventName=${eventName}`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'token': tokenEl.value
                    },
                    body: JSON.stringify(messageData)
                });

                if (response.ok) {
                    const result = await response.json();
                    log(`消息发送给用户 ${targetUserId} 成功: ${JSON.stringify(result)}`);
                    addMessage('success', '消息发送', `目标用户: ${targetUserId}\n事件: ${eventName}\n数据: ${JSON.stringify(messageData, null, 2)}`);
                } else {
                    throw new Error(`HTTP ${response.status}`);
                }
            } catch (error) {
                log(`消息发送失败: ${error.message}`);
                addMessage('error', '消息发送失败', error.message);
            }
        }

        // 广播消息
        async function broadcastMessage() {
            const eventName = eventNameEl.value.trim();
            const data = messageDataEl.value.trim();

            if (!eventName || !data) {
                alert('请填写事件名称和消息数据');
                return;
            }

            try {
                let messageData;
                try {
                    messageData = JSON.parse(data);
                } catch (e) {
                    messageData = data;
                }

                const response = await fetch(`${baseUrlEl.value}/api/client/sse/broadcast?eventName=${eventName}`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'token': tokenEl.value
                    },
                    body: JSON.stringify(messageData)
                });

                if (response.ok) {
                    const result = await response.json();
                    log(`广播消息成功: ${JSON.stringify(result)}`);
                    addMessage('success', '广播消息', `事件: ${eventName}\n数据: ${JSON.stringify(messageData, null, 2)}`);
                } else {
                    throw new Error(`HTTP ${response.status}`);
                }
            } catch (error) {
                log(`广播消息失败: ${error.message}`);
                addMessage('error', '广播消息失败', error.message);
            }
        }

        // 清空消息
        function clearMessages() {
            messagesEl.innerHTML = '';
            messageCount = 0;
            updateMessageCount();
        }

        // 事件处理器
        function handleConnected(data) {
            updateStatus('connected', '已连接');
            updateButtons(false, true);
            updateStats();
            addMessage('success', '连接成功', JSON.stringify(data, null, 2));
            startHeartbeat();
        }

        function handleDisconnected(data) {
            updateStatus('disconnected', '连接已断开');
            updateButtons(false, false);
            updateStats();
            addMessage('warning', '连接断开', JSON.stringify(data, null, 2));
            clearHeartbeat();
        }

        function handleError(data) {
            updateStatus('disconnected', '连接错误');
            updateButtons(false, false);
            updateStats();
            addMessage('error', '连接错误', JSON.stringify(data, null, 2));
            clearHeartbeat();
        }

        function handleMessage(data) {
            messageCount++;
            updateMessageCount();
            
            // 处理stream事件
            if (data.event === 'stream') {
                appendStreamOutput(data.data);
            } else if (data.event === 'complete') {
                appendStreamOutput(`[完成] ${data.data}`);
                log('流式输出完成');
            } else {
                addMessage('', data.event, JSON.stringify(data, null, 2));
            }
        }

        function handleReconnected(data) {
            updateStatus('connected', '重连成功');
            updateButtons(false, true);
            updateStats();
            addMessage('success', '重连成功', JSON.stringify(data, null, 2));
            startHeartbeat();
        }

        function handleReconnectFailed(data) {
            updateStatus('disconnected', '重连失败');
            updateButtons(false, false);
            updateStats();
            addMessage('error', '重连失败', JSON.stringify(data, null, 2));
            clearHeartbeat();
        }

        // 更新状态
        function updateStatus(type, text) {
            statusEl.className = `status ${type}`;
            statusEl.textContent = text;
        }

        // 更新按钮状态
        function updateButtons(connecting, connected) {
            connectBtn.disabled = connecting || connected;
            disconnectBtn.disabled = !connected;
            heartbeatBtn.disabled = !connected;
            sendMessageBtn.disabled = !connected;
            sendToUserBtn.disabled = !connected;
            broadcastBtn.disabled = !connected;
        }

        // 更新统计信息
        function updateStats() {
            if (sseClient) {
                const status = sseClient.getStatus();
                sessionIdEl.textContent = status.sessionId || '-';
                userIdEl.textContent = status.userId || '-';
                reconnectAttemptsEl.textContent = status.reconnectAttempts || 0;
            } else {
                sessionIdEl.textContent = '-';
                userIdEl.textContent = '-';
                reconnectAttemptsEl.textContent = '0';
            }
        }

        // 更新消息计数
        function updateMessageCount() {
            messageCountEl.textContent = messageCount;
        }

        // 添加消息
        function addMessage(type, eventType, data) {
            const messageEl = document.createElement('div');
            messageEl.className = `message ${type}`;
            
            const timestamp = new Date().toLocaleTimeString();
            messageEl.innerHTML = `
                <div class="timestamp">${timestamp}</div>
                <div class="event-type">${eventType}</div>
                <div class="data">${data}</div>
            `;
            
            messagesEl.appendChild(messageEl);
            messagesEl.scrollTop = messagesEl.scrollHeight;
        }

        // 添加日志
        function log(message) {
            const timestamp = new Date().toLocaleTimeString();
            logEl.textContent += `[${timestamp}] ${message}\n`;
            logEl.scrollTop = logEl.scrollHeight;
        }

        // 开始心跳
        function startHeartbeat() {
            if (heartbeatInterval) {
                clearInterval(heartbeatInterval);
            }
            heartbeatInterval = setInterval(sendHeartbeat, 30000); // 30秒发送一次心跳
        }

        // 清除心跳
        function clearHeartbeat() {
            if (heartbeatInterval) {
                clearInterval(heartbeatInterval);
                heartbeatInterval = null;
            }
        }

        // 测试流式输出
        async function testStream() {
            const message = testMessageEl.value.trim();
            let sessionId = testSessionIdEl.value.trim();
            
            if (!message) {
                alert('请输入测试消息');
                return;
            }
            
            // 如果没有提供sessionId，使用当前连接的sessionId
            if (!sessionId && sseClient && sseClient.sessionId) {
                sessionId = sseClient.sessionId;
                testSessionIdEl.value = sessionId;
                log(`使用当前连接的sessionId: ${sessionId}`);
            }
            
            try {
                log('开始测试流式输出...');
                clearStreamOutput();
                appendStreamOutput('开始连接流式输出...\n');
                
                // 发送POST请求触发流式输出
                const requestData = {
                    desc: message
                };
                
                const url = `${baseUrlEl.value}/api/client/index/generateUserLocation?sessionId=${encodeURIComponent(sessionId || '')}`;
                log(`请求URL: ${url}`);
                log(`请求数据: ${JSON.stringify(requestData)}`);
                
                const response = await fetch(url, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Accept': 'text/event-stream',
                        'Cache-Control': 'no-cache'
                    },
                    body: JSON.stringify(requestData)
                });
                
                log(`响应状态: ${response.status} ${response.statusText}`);
                log(`响应头: ${JSON.stringify(Object.fromEntries(response.headers.entries()))}`);
                
                if (!response.ok) {
                    const errorText = await response.text();
                    throw new Error(`HTTP ${response.status}: ${errorText}`);
                }
                
                log('开始读取SSE流式响应...');
                appendStreamOutput('连接成功，开始接收数据...\n');
                
                // 处理SSE流式响应
                const reader = response.body.getReader();
                const decoder = new TextDecoder();
                let buffer = '';
                let lineCount = 0;
                let totalBytes = 0;
                let chunkCount = 0;
                
                while (true) {
                    const { done, value } = await reader.read();
                    
                    if (done) {
                        log('流式输出完成');
                        appendStreamOutput('\n[完成] 流式输出结束');
                        break;
                    }
                    
                    chunkCount++;
                    // 解码新的数据块并添加到缓冲区
                    const newChunk = decoder.decode(value, { stream: true });
                    buffer += newChunk;
                    totalBytes += value.length;
                    
                    log(`接收到第${chunkCount}个数据块: ${newChunk.length} 字符，总计: ${totalBytes} 字节`);
                    log(`数据块内容: ${newChunk.substring(0, 200)}${newChunk.length > 200 ? '...' : ''}`);
                    
                    // 按行分割并处理
                    const lines = buffer.split('\n');
                    // 保留最后一行（可能不完整）
                    buffer = lines.pop() || '';
                    
                    for (const line of lines) {
                        if (line.trim()) {
                            lineCount++;
                            log(`处理第${lineCount}行: ${line.substring(0, 100)}...`);
                            
                            // 直接显示原始行内容
                            appendStreamOutput(line);
                        }
                    }
                    
                    // 如果缓冲区有内容但没有换行符，也显示出来
                    if (buffer && !buffer.includes('\n')) {
                        log(`显示缓冲区内容: ${buffer}`);
                        appendStreamOutput(buffer);
                        buffer = '';
                    }
                }
                
                log(`流式处理完成，共接收${chunkCount}个数据块，处理${lineCount}行，总计${totalBytes}字节`);
                
            } catch (error) {
                log(`流式输出测试失败: ${error.message}`);
                appendStreamOutput(`\n[错误] ${error.message}`);
            }
        }
        
        // 清空流式输出
        function clearStreamOutput() {
            streamOutputEl.innerHTML = '';
        }
        
        // 追加流式输出内容
        function appendStreamOutput(content) {
            // 如果是换行符，直接添加到现有内容
            if (content === '\n') {
                streamOutputEl.textContent += '\n';
            } else if (content.endsWith('\n')) {
                // 如果内容以换行符结尾，去掉换行符并添加带时间戳的行
                const textContent = content.slice(0, -1);
                if (textContent.trim()) {
                    const timestamp = new Date().toLocaleTimeString();
                    const outputLine = document.createElement('div');
                    outputLine.innerHTML = `<span style="color: #666;">[${timestamp}]</span> ${textContent}`;
                    streamOutputEl.appendChild(outputLine);
                }
            } else {
                // 普通内容，添加带时间戳的新行
                if (content.trim()) {
                    const timestamp = new Date().toLocaleTimeString();
                    const outputLine = document.createElement('div');
                    outputLine.innerHTML = `<span style="color: #666;">[${timestamp}]</span> ${content}`;
                    streamOutputEl.appendChild(outputLine);
                }
            }
            
            // 自动滚动到底部
            streamOutputEl.scrollTop = streamOutputEl.scrollHeight;
            
            // 强制重绘以确保内容立即显示
            streamOutputEl.style.display = 'none';
            streamOutputEl.offsetHeight; // 触发重排
            streamOutputEl.style.display = 'block';
        }

        // 用户位置分析相关元素
        const userLocationMessageEl = document.getElementById('userLocationMessage');
        const userLocationOutputEl = document.getElementById('userLocationOutput');
        const userLocationBtn = document.getElementById('userLocationBtn');
        const clearUserLocationBtn = document.getElementById('clearUserLocationBtn');

        // 用户位置分析
        async function analyzeUserLocation() {
            const message = userLocationMessageEl.value.trim();
            
            if (!message) {
                alert('请输入用户信息描述');
                return;
            }
            
            try {
                log('开始分析用户位置...');
                clearUserLocationOutput();
                
                const requestData = {
                    message: message
                };
                
                const response = await fetch(`${baseUrlEl.value}/api/client/index/addUserLocation`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(requestData)
                });
                
                if (!response.ok) {
                    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
                }
                
                const result = await response.json();
                
                if (result.code === 200) {
                    log('用户位置分析成功');
                    appendUserLocationOutput('分析结果:\n');
                    appendUserLocationOutput(JSON.stringify(result.data, null, 2));
                } else {
                    throw new Error(result.message || '分析失败');
                }
                
            } catch (error) {
                log(`用户位置分析失败: ${error.message}`);
                appendUserLocationOutput(`错误: ${error.message}`);
            }
        }
        
        // 清空用户位置分析结果
        function clearUserLocationOutput() {
            userLocationOutputEl.innerHTML = '';
        }
        
        // 追加用户位置分析结果
        function appendUserLocationOutput(content) {
            userLocationOutputEl.textContent += content;
            userLocationOutputEl.scrollTop = userLocationOutputEl.scrollHeight;
        }

        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', init);
    </script>
</body>
</html> 